home *** CD-ROM | disk | FTP | other *** search
/ Aminet 37 / Aminet 37 (2000)(Schatztruhe)[!][Jun 2000].iso / Aminet / dev / lang / sofa.lha / sofa / smalleiffel / lib_std / string.e < prev    next >
Text File  |  2000-03-25  |  40KB  |  1,548 lines

  1. -- This file is  free  software, which  comes  along  with  SmallEiffel. This
  2. -- software  is  distributed  in the hope that it will be useful, but WITHOUT 
  3. -- ANY  WARRANTY;  without  even  the  implied warranty of MERCHANTABILITY or
  4. -- FITNESS  FOR A PARTICULAR PURPOSE. You can modify it as you want, provided
  5. -- this header is kept unaltered, and a notification of the changes is added.
  6. -- You  are  allowed  to  redistribute  it and sell it, alone or as a part of 
  7. -- another product.
  8. --          Copyright (C) 1994-98 LORIA - UHP - CRIN - INRIA - FRANCE
  9. --            Dominique COLNET and Suzanne COLLIN - colnet@loria.fr 
  10. --                       http://SmallEiffel.loria.fr
  11. --
  12. class STRING
  13.    --
  14.    -- Resizable character STRINGs. 
  15.    --
  16.    
  17. inherit
  18.    HASHABLE;
  19.    COMPARABLE 
  20.       redefine 
  21.          is_equal, copy, compare, three_way_comparison, 
  22.          out_in_tagged_out_memory, fill_tagged_out_memory
  23.       end;
  24.    
  25. creation make, copy, blank, from_external, from_external_copy,
  26.    make_from_string
  27.  
  28. feature {STRING}
  29.    
  30.    storage: NATIVE_ARRAY[CHARACTER];
  31.          -- The place where characters are stored.
  32.    
  33. feature 
  34.    
  35.    count: INTEGER;
  36.          -- String length.
  37.    
  38.    capacity: INTEGER;
  39.          -- Capacity of the `storage' area.
  40.    
  41. feature -- Creation / Modification :
  42.    
  43.    make(needed_capacity: INTEGER) is
  44.          -- Initialize the string to have at least `needed_capacity'
  45.          -- characters of storage.
  46.       require
  47.           non_negative_size: needed_capacity >= 0;
  48.       do
  49.          if needed_capacity > 0 then
  50.             if capacity < needed_capacity then
  51.                storage := storage.calloc(needed_capacity);
  52.                capacity := needed_capacity;
  53.             end;
  54.          end;
  55.          count := 0;
  56.       ensure
  57.          needed_capacity <= capacity;
  58.          empty_string: count = 0
  59.       end;
  60.  
  61.    blank(nr_blanks: INTEGER) is
  62.          -- Initialize string with `nr_blanks' blanks.
  63.       require
  64.          nr_blanks >= 0;
  65.       do
  66.          make(nr_blanks);
  67.          count := nr_blanks;
  68.          fill_with(' ');
  69.       ensure
  70.          count = nr_blanks;
  71.          nb_occurrences(' ') = count
  72.       end;
  73.  
  74. feature -- Testing :
  75.    
  76.    is_empty: BOOLEAN is
  77.          -- Has string length 0 ?
  78.       do
  79.          Result := (count = 0);
  80.       end;
  81.  
  82.    empty: BOOLEAN is
  83.       obsolete "The new name of this feature is `is_empty'."
  84.       do
  85.          Result := is_empty;
  86.       end;
  87.  
  88.    item, infix "@" (index: INTEGER): CHARACTER is
  89.          -- Character at position `index'.
  90.       require
  91.          valid_index(index)
  92.       do
  93.          Result := storage.item(index - 1);
  94.       end;
  95.  
  96.    valid_index(index: INTEGER): BOOLEAN is
  97.          -- True when `index' is valid (i.e., inside actual bounds).
  98.       do
  99.          Result := 1 <= index and then index <= count;
  100.       ensure
  101.          Result = (1 <= index and then index <= count)
  102.       end;
  103.    
  104.    hash_code: INTEGER is
  105.       local
  106.          i: INTEGER;
  107.       do
  108.          i := count;
  109.          if i > 5 then
  110.             Result := i * item(i).code;
  111.             i := 5;
  112.          end;
  113.          from until i <= 0 loop
  114.             Result := Result + item(i).code;
  115.             i := i - 1;
  116.          end;
  117.          Result := Result * count;
  118.       end;
  119.  
  120.    infix "<" (other: like Current): BOOLEAN is
  121.          -- Is Current less than `other' ?
  122.       local
  123.          i: INTEGER;
  124.       do
  125.          from  
  126.             i := 1;
  127.          until
  128.             count < i or else other.count < i 
  129.             or else item(i) /= other.item(i)
  130.          loop
  131.             i := i + 1;
  132.          end;
  133.          if count < i then
  134.             Result := other.count >= i;
  135.          elseif other.count < i then
  136.             Result := false;
  137.          else
  138.             Result := item(i) < other.item(i);
  139.          end;
  140.       end;
  141.  
  142.    compare, three_way_comparison(other: like Current): INTEGER is
  143.       local
  144.          i: INTEGER;
  145.       do
  146.          from  
  147.             i := 1;
  148.          until
  149.             count < i or else other.count < i 
  150.             or else item(i) /= other.item(i)
  151.          loop
  152.             i := i + 1;
  153.          end;
  154.          if count < i then
  155.             if other.count < i then
  156.             else
  157.                Result := -1;
  158.             end;
  159.          elseif other.count < i then
  160.             Result := 1;
  161.          elseif item(i) < other.item(i) then
  162.             Result := -1;
  163.          else
  164.             Result := 1;
  165.          end;
  166.       end;
  167.  
  168.    same_as(other: STRING): BOOLEAN is
  169.          -- Case insensitive `is_equal'.
  170.       require
  171.          other /= Void
  172.       local
  173.          s1, s2: like storage;
  174.          i: INTEGER;
  175.       do
  176.          i := count;
  177.          if i = other.count then
  178.             if storage.fast_memcmp(other.storage,i) then
  179.                Result := true;
  180.             else
  181.                from
  182.                   i := i - 1;
  183.                   s1 := storage;
  184.                   s2 := other.storage;
  185.                   Result := true;
  186.                until
  187.                   i < 0
  188.                loop
  189.                   if s1.item(i).same_as(s2.item(i)) then
  190.                      i := i - 1;
  191.                   else
  192.                      i := -1;
  193.                      Result := false;
  194.                   end;
  195.                end;
  196.             end;
  197.          end;
  198.       end;
  199.    
  200.    is_equal(other: like Current): BOOLEAN is
  201.          -- Has Current the same text as `other' ?
  202.       do
  203.          if count = other.count then
  204.             Result := storage.fast_memcmp(other.storage,count);
  205.          end;
  206.       end;
  207.    
  208.    index_of(ch: CHARACTER): INTEGER is
  209.          -- Gives the index of the first occurrence `ch' or 
  210.          -- `count + 1' if none.
  211.       do
  212.          Result := 1 + storage.fast_index_of(ch,count - 1);
  213.       ensure
  214.          (Result /= count + 1) implies (item(Result) = ch);
  215.       end;
  216.    
  217.    index_of_string(other: STRING): INTEGER is
  218.          -- Position of the first occurrence of `other'
  219.          -- or `count + 1' if none.
  220.       require
  221.          not other.is_empty
  222.       local
  223.          stop: BOOLEAN;
  224.          i1, i2, i3: INTEGER;
  225.       do
  226.          from
  227.             i1 := 1;
  228.             i2 := other.count;
  229.             i3 := i2;
  230.          invariant
  231.             i3 = i2 - i1 + 1; 
  232.          variant
  233.             count - i1 + 1
  234.          until
  235.             Result /= 0
  236.          loop
  237.             if i2 > count then
  238.                Result := count + 1;
  239.             else
  240.                from
  241.                   stop := false;
  242.                invariant
  243.                   i3 = i2 - i1 + 1
  244.                variant
  245.                   (i3 + i2)
  246.                until
  247.                   stop
  248.                loop
  249.                   if i3 = 0 then
  250.                      stop := true;
  251.                      Result := i1;
  252.                   elseif other.item(i3) /= item(i2) then
  253.                      stop := true;
  254.                   end;
  255.                   i3 := i3 - 1;
  256.                   i2 := i2 - 1;
  257.                end;
  258.             end;
  259.             i1 := i1 + 1;
  260.             i3 := other.count;
  261.             i2 := i1 + i3 - 1;
  262.          end;
  263.       end;
  264.  
  265.    has(ch: CHARACTER): BOOLEAN is
  266.          -- True if `ch' is in the STRING.
  267.       do
  268.          Result := storage.fast_has(ch,count - 1);
  269.       end;
  270.  
  271.    has_string(other: STRING): BOOLEAN is
  272.          -- True if `other' is in the STRING.
  273.       do
  274.          Result := index_of_string(other) /= (count + 1);
  275.       end;
  276.  
  277.    nb_occurrences, occurrences_of, occurrences(c: CHARACTER): INTEGER is
  278.          -- Number of times character `c' appears in the string.
  279.       do
  280.          Result := storage.fast_nb_occurrences(c,count - 1);
  281.       ensure
  282.          Result >= 0
  283.       end;
  284.    
  285.    has_suffix(s: STRING): BOOLEAN is
  286.          -- True if suffix of Current is `s'.
  287.       require
  288.          s /= Void
  289.       local
  290.          i1, i2: INTEGER;
  291.       do
  292.          if s.count <= count then
  293.             from  
  294.                i1 := count - s.count + 1;
  295.                i2 := 1;
  296.             until
  297.                i1 > count or else
  298.                i2 > s.count or else
  299.                item(i1) /= s.item(i2)
  300.             loop
  301.                i1 := i1 + 1;
  302.                i2 := i2 + 1;
  303.             end;
  304.             Result := i1 > count; 
  305.          end;
  306.       end;
  307.    
  308.    has_prefix(p: STRING): BOOLEAN is
  309.          -- True if prefix of Current is `p'.
  310.       require
  311.          p /= Void;
  312.       local
  313.          i: INTEGER;
  314.       do
  315.          if p.count <= count then
  316.             from  
  317.                i := p.count;
  318.             until
  319.                i = 0 or else item(i) /= p.item(i)
  320.             loop
  321.                i := i - 1;
  322.             end;
  323.             Result := i = 0; 
  324.          end;
  325.       end;
  326.  
  327.    replace_all(old_character, new_character: like item) is
  328.          -- Replace all occurrences of the element `old_character' by 
  329.          -- `new_character'.
  330.       do
  331.          storage.fast_replace_all(old_character,new_character,count - 1);
  332.       ensure
  333.          count = old count;
  334.          nb_occurrences(old_character) = 0
  335.       end;
  336.  
  337.    is_integer: BOOLEAN is
  338.       -- Can contents be read as an INTEGER ?
  339.       local
  340.          i, state: INTEGER;
  341.          cc: CHARACTER;
  342.       do
  343.          -- state 0 : nothing read.
  344.          -- state 1 : "+" or "-" read.
  345.          -- state 2 : in the number.
  346.          -- state 3 : after the number.
  347.          -- state 4 : error.
  348.          from
  349.             i := 1;
  350.          until
  351.             i > count or else state = 4
  352.          loop
  353.             cc := item(i);
  354.             inspect 
  355.                state
  356.             when 0 then
  357.                if cc.is_separator then
  358.                elseif cc = '+' then
  359.                   state := 1;
  360.                elseif cc = '-' then
  361.                   state := 1;
  362.                elseif cc.is_digit then
  363.                   state := 2;
  364.                   Result := true;
  365.                else
  366.                   state := 4;
  367.                   Result := false;
  368.                end;
  369.             when 1 then
  370.                if cc.is_separator then
  371.                elseif cc.is_digit then
  372.                   state := 2;
  373.                   Result := true;
  374.                else
  375.                   state := 4;
  376.                   Result := false;
  377.                end;
  378.             when 2 then
  379.                if cc.is_digit then
  380.                elseif cc.is_separator then
  381.                   state := 3;
  382.                else
  383.                   state := 4;
  384.                   Result := false;
  385.                end;
  386.             when 3 then
  387.                if cc.is_separator then
  388.                else 
  389.                   state := 4;
  390.                   Result := false;
  391.                end;
  392.             end;
  393.             i := i + 1;
  394.          end;
  395.       end; 
  396.  
  397.    is_real: BOOLEAN is
  398.          -- Can contents be read as a REAL ?
  399.       local
  400.          d: DOUBLE;
  401.       do
  402.          if is_double then
  403.             d := to_double
  404.             if Minimum_real <= d and then d <= Maximum_real then
  405.                Result := true
  406.                -- This gives only approximate accuracy; the comparison 
  407.                -- is not accurate to nearly as many significant figures
  408.                -- as are displayed for the limits.
  409.             end
  410.          end
  411.       end
  412.  
  413.    is_double: BOOLEAN is
  414.          -- Can contents be read as a DOUBLE ?
  415.       local
  416.          i, state: INTEGER;
  417.          cc: CHARACTER;
  418.          begun: BOOLEAN;
  419.       do
  420.          -- state 0 : nothing read.
  421.          -- state 1 : "+" or "-" read.
  422.          -- state 2 : in the number.
  423.          -- state 3 : decimal point read
  424.          -- state 4 : in fractional part
  425.          -- state 5 : read 'E' or 'e' for scientific notation
  426.          -- state 6 : read "-" sign of exponent
  427.          -- state 7 : in exponent
  428.          -- state 8 : after the number.
  429.          -- state 9 : error.
  430.          from
  431.             i := 1;
  432.          until
  433.             i > count or else state = 9
  434.          loop
  435.             cc := item(i);
  436.             inspect 
  437.                state
  438.             when 0 then
  439.                if cc.is_separator then
  440.                elseif cc = '+' then
  441.                   state := 1;
  442.                elseif cc = '-' then
  443.                   state := 1;
  444.                elseif cc.is_digit then
  445.                   state := 2;
  446.                   Result := true;
  447.                elseif cc = '.' then
  448.                   state := 3
  449.                else
  450.                   state := 9;
  451.                   Result := false;
  452.                end;
  453.             when 1 then
  454.                if cc.is_separator then
  455.                elseif cc.is_digit then
  456.                   state := 2;
  457.                   Result := true;
  458.                elseif cc = '.' then
  459.                   state := 3
  460.                else
  461.                   state := 9;
  462.                   Result := false;
  463.                end;
  464.             when 2 then
  465.                if cc.is_digit then
  466.                   begun := true
  467.                elseif cc = '.' then
  468.                   state := 3
  469.                else
  470.                   state := 9;
  471.                   Result := false;
  472.                end;
  473.             when 3 then
  474.                if cc.is_separator then
  475.                   state := 8;
  476.                elseif cc.is_digit then
  477.                   state := 4
  478.                   Result := true;
  479.                   begun := true
  480.                else
  481.                   state := 9
  482.                   Result := false
  483.                end
  484.             when 4 then
  485.                if cc.is_digit then
  486.                   begun := true
  487.                elseif cc.is_separator then
  488.                   state := 8;
  489.                elseif (cc = 'e' or cc = 'E') and begun then
  490.                   state := 5
  491.                else
  492.                   state := 9;
  493.                   Result := false;
  494.                end;
  495.             when 5 then
  496.                if cc = '-' then
  497.                   state := 6
  498.                elseif cc.is_digit then
  499.                   state := 7
  500.                else
  501.                   state := 9;
  502.                   Result := false;
  503.                end;
  504.             when 6 then
  505.                if cc.is_digit then
  506.                   state := 7
  507.                else
  508.                   state := 9;
  509.                   Result := false;
  510.                end;
  511.             when 7 then
  512.                if cc.is_digit then
  513.                elseif cc.is_separator then
  514.                   state := 8
  515.                else
  516.                   state := 9;
  517.                   Result := false;
  518.                end;
  519.             when 8 then
  520.                if cc.is_separator then
  521.                else 
  522.                   state := 9;
  523.                   Result := false;
  524.                end;
  525.             end;
  526.             i := i + 1;
  527.          end;
  528.          if state < 3 then
  529.             -- exclude integers
  530.             Result := false
  531.          end
  532.          -- We should check the value is within the system limits, but
  533.          -- I can't see how to do that without trying to convert it.
  534.       end; 
  535.  
  536.    is_bit: BOOLEAN is
  537.          -- True when the contents is a sequence of bits (i.e., mixed 
  538.          -- characters `0' and characters `1').
  539.       local
  540.          i: INTEGER;
  541.       do
  542.          from
  543.             i := count;
  544.             Result := true;
  545.          until
  546.             not Result or else i = 0
  547.          loop
  548.             Result := item(i).is_bit;
  549.             i := i - 1;
  550.          end;
  551.       ensure
  552.          Result = (count = nb_occurrences('0') + nb_occurrences('1'))
  553.       end;
  554.  
  555. feature -- Modification :
  556.  
  557.    resize(new_count: INTEGER) is
  558.          -- Resize Current. When `new_count' is greater than
  559.          -- `count', new positions are initialized with the
  560.          -- default value of type CHARACTER ('%U').
  561.       require
  562.          new_count >= 0
  563.       local
  564.      s: like storage;
  565.       do
  566.          if new_count <= count then
  567.             count := new_count;
  568.      elseif capacity < new_count then
  569.         if capacity = 0 then
  570.            storage := storage.calloc(new_count);
  571.         else
  572.            storage := storage.realloc(capacity,new_count);
  573.         end;
  574.         capacity := new_count;
  575.         count := new_count;
  576.          else
  577.         storage.clear(count,new_count - 1);
  578.         count := new_count
  579.      end;
  580.       ensure
  581.          count = new_count;
  582.          capacity >= old capacity
  583.       end;
  584.    
  585.    clear, wipe_out is
  586.          -- Clear out the current STRING.
  587.          -- Note : internal `storage' memory is neither released nor shrunk.
  588.       do
  589.          count := 0;
  590.       ensure
  591.          count = 0;
  592.       end;
  593.    
  594.    copy(other: like Current) is
  595.          -- Copy `other' onto Current.
  596.       do
  597.          count := other.count;
  598.          if count > 0 then
  599.             if capacity < count then
  600.                storage := storage.calloc(count);
  601.                capacity := count;
  602.             end;
  603.             storage.copy_from(other.storage,count-1);
  604.          end;
  605.       ensure then
  606.          count = other.count
  607.       end;
  608.  
  609.    fill, fill_with(c: CHARACTER) is
  610.          -- Replace every character with `c'.
  611.       do
  612.          storage.set_all_with(c,count - 1);
  613.       ensure
  614.          nb_occurrences(c) = count
  615.       end;
  616.    
  617.    fill_blank is 
  618.          -- Fill entire string with blanks
  619.       do  
  620.          fill_with(' ');
  621.       ensure
  622.          nb_occurrences(' ') = count
  623.       end;     
  624.  
  625.    append, append_string(other: STRING) is
  626.          -- Append `other' to Current.
  627.       require
  628.          other /= Void
  629.       local
  630.          other_count, needed_capacity: INTEGER;
  631.       do
  632.          other_count := other.count;
  633.          needed_capacity := count + other_count;
  634.          if capacity < needed_capacity then
  635.             if capacity = 0 then
  636.                capacity := needed_capacity;
  637.                storage := storage.calloc(capacity);
  638.             else
  639.                storage := storage.realloc(capacity,needed_capacity);
  640.                capacity := needed_capacity;
  641.             end;
  642.          end;
  643.          storage.copy_at(count,other.storage,other_count);
  644.          count := needed_capacity;
  645.       end;
  646.  
  647.    prepend(other: STRING) is
  648.          -- Prepend `other' to Current
  649.       require
  650.          other /= Void
  651.       local
  652.          i, j: INTEGER;
  653.       do
  654.      i := count;
  655.      j := other.count;
  656.      resize(i + j);
  657.      if i > 0 and then j > 0 then
  658.         storage.move(0, i - 1, j);
  659.      end;
  660.      storage.copy_from(other.storage, j - 1);
  661.       ensure 
  662.      Current.is_equal((old other.twin) + (old Current.twin))
  663.       end;
  664.  
  665.    infix "+" (other: STRING): STRING is
  666.          -- Create a new STRING which is the concatenation of 
  667.          -- `Current' and `other'.
  668.       require
  669.          other /= Void
  670.       do
  671.          !!Result.make(count + other.count);
  672.          Result.append(Current);
  673.          Result.append(other);
  674.       ensure
  675.          Result.count = count + other.count
  676.       end;
  677.    
  678.    put(ch: CHARACTER; index: INTEGER) is
  679.          -- Put `ch' at position `index'.
  680.       require
  681.          valid_index(index)
  682.       do
  683.          storage.put(ch,index - 1);
  684.       ensure
  685.          item (index) = ch
  686.       end;
  687.    
  688.    swap(i1, i2: INTEGER) is
  689.       require
  690.          valid_index(i1);
  691.          valid_index(i2)
  692.       local
  693.          tmp: CHARACTER;
  694.       do
  695.          tmp := item(i1);
  696.          put(item(i2),i1);
  697.          put(tmp,i2);
  698.       ensure
  699.          item(i1) = old item(i2);
  700.          item(i2) = old item(i1);
  701.       end;
  702.    
  703.    insert(ch: CHARACTER; index: INTEGER) is
  704.          -- Insert `ch' after position `index'.
  705.       require
  706.          0 <= index and index <= count;
  707.       local
  708.          i: INTEGER;
  709.       do
  710.          from  
  711.             i := count;
  712.             extend(' ');
  713.          until
  714.             i = index
  715.          loop
  716.             put(item(i),i + 1);
  717.             i := i - 1;
  718.          end;
  719.          put(ch,index + 1);
  720.       ensure
  721.          item (index + 1) = ch
  722.       end;
  723.  
  724.    shrink(min_index, max_index: INTEGER) is
  725.          -- Keep only the slice [`min_index' .. `max_index'] or nothing
  726.          -- when the slice is empty.
  727.       require
  728.          1 <= min_index;
  729.          max_index <= count;
  730.          min_index <= max_index + 1
  731.       do
  732.          if max_index < min_index then
  733.             count := 0;
  734.          elseif min_index = 1 then
  735.             count := max_index;
  736.          else
  737.         storage.copy_slice(0,storage,min_index - 1,max_index - 1);
  738.         count := max_index - min_index + 1
  739.          end;
  740.       ensure
  741.          count = max_index - min_index + 1;
  742.       end;
  743.    
  744.    remove(index: INTEGER) is
  745.          -- Remove character at position `index'.
  746.       require
  747.          valid_index(index)
  748.       do
  749.          remove_between(index,index);
  750.       ensure
  751.          count = (old count) - 1
  752.       end;
  753.  
  754.    add_first(ch: CHARACTER) is
  755.          -- Add `ch' at first position.
  756.       local
  757.          i: INTEGER;
  758.       do
  759.          from  
  760.             extend(' ');
  761.             i := count;
  762.          until
  763.             i = 1
  764.          loop
  765.             put(item(i - 1),i);
  766.             i := i - 1;
  767.          end;
  768.          put(ch,1);
  769.       ensure
  770.          count = 1 + old count;
  771.          item(1) = ch
  772.       end;
  773.  
  774.    add_last, extend, append_character(ch: CHARACTER) is
  775.          -- Append `ch' to string
  776.       local
  777.          new_capacity: INTEGER;
  778.       do
  779.          if capacity > count then
  780.          elseif capacity = 0 then
  781.             capacity := 32;
  782.             storage := storage.calloc(capacity);
  783.          else
  784.             new_capacity := 2 * capacity;
  785.             storage := storage.realloc(capacity,new_capacity);
  786.             capacity := new_capacity;
  787.          end;
  788.          storage.put(ch,count);
  789.          count := count + 1;
  790.       ensure
  791.          count = 1 + old count;
  792.          item (count) = ch
  793.       end;
  794.  
  795.    precede(ch: CHARACTER) is
  796.          -- Prepend `ch' to string
  797.       local
  798.          i: INTEGER;
  799.       do
  800.          from  
  801.             extend(' ');
  802.             i := count;
  803.          until
  804.             i = 1
  805.          loop
  806.             put(item(i-1),i);
  807.             i := i - 1;
  808.          end;
  809.          put(ch,1);
  810.       ensure
  811.          item (1) = ch
  812.       end;
  813.  
  814.    to_lower is
  815.          -- Convert all characters to lower case.
  816.       local
  817.          i: INTEGER;
  818.       do
  819.          from  
  820.             i := count;
  821.          until
  822.             i = 0
  823.          loop
  824.             put(item(i).to_lower,i);
  825.             i := i - 1;
  826.          end;
  827.       end;
  828.    
  829.    to_upper is
  830.          -- Convert all characters to upper case.
  831.       local
  832.          i: INTEGER;
  833.       do
  834.          from  
  835.             i := count;
  836.          until
  837.             i = 0
  838.          loop
  839.             put(item(i).to_upper,i);
  840.             i := i - 1;
  841.          end;
  842.       end;
  843.  
  844.    remove_first(nb: INTEGER) is
  845.          -- Remove `nb' first characters.
  846.       require
  847.          nb >= 0; 
  848.          count >= nb;
  849.       do
  850.          if nb > 0 then
  851.             remove_between(1, nb)
  852.          end;
  853.       ensure
  854.          count = (old count) - nb
  855.       end; 
  856.    
  857.    remove_last(nb: INTEGER) is
  858.          -- Remove `nb' last characters.
  859.       require
  860.          0 <= nb;
  861.          nb <= count;
  862.       do
  863.          count := count - nb;
  864.       ensure
  865.          count = old count - nb
  866.       end; 
  867.    
  868.    remove_between(low, up : INTEGER) is
  869.          -- Remove character between positions `low' and `up'.
  870.       require
  871.          valid_index(low);
  872.          valid_index(up);
  873.          low <= up
  874.       local
  875.          i : INTEGER;
  876.       do
  877.          from  
  878.             i := up;
  879.          until
  880.             i >= count
  881.          loop
  882.             put(item(i + 1), low + i - up);
  883.             i := i + 1;
  884.          end;
  885.          count := count - (up - low + 1);
  886.       ensure
  887.          count = (old count) - (up - low + 1)
  888.       end;
  889.  
  890.    remove_suffix(s: STRING) is
  891.       -- Remove the suffix `s' of current string.
  892.       require
  893.          has_suffix(s);
  894.       do
  895.          remove_last(s.count);
  896.       ensure
  897.          (old Current.twin).is_equal(Current + (old s.twin))
  898.       end;
  899.  
  900.    remove_prefix(s: STRING) is
  901.       -- Remove the prefix `s' of current string.
  902.       require
  903.          has_prefix(s);
  904.       do
  905.          remove_first(s.count);
  906.       ensure
  907.          (old Current.twin).is_equal((old s.twin) + Current)
  908.       end;
  909.  
  910.    left_adjust is
  911.          -- Remove leading blanks.
  912.       local
  913.          i: INTEGER;
  914.       do
  915.          from
  916.          until
  917.             i + 1 > count or else item(i + 1) /= ' '
  918.          loop
  919.             i := i + 1;
  920.          end;
  921.          remove_first(i);
  922.       ensure
  923.          stripped: is_empty or else item (1) /= ' '
  924.       end;
  925.  
  926.    right_adjust is
  927.          -- Remove trailing blanks.
  928.       do
  929.          from
  930.          until
  931.             count = 0 or else item(count) /= ' '
  932.          loop
  933.             count := count - 1;
  934.          end
  935.       ensure
  936.          stripped: is_empty or else item (count) /= ' '
  937.       end;
  938.  
  939. feature -- Features which don't modify the string
  940.  
  941.    first: CHARACTER is
  942.       require
  943.          not is_empty
  944.       do
  945.          Result := storage.item(0);
  946.       end;
  947.  
  948.    last: CHARACTER is
  949.       require
  950.          not is_empty;
  951.       do
  952.          Result := item(count);
  953.       end;
  954.  
  955. feature -- Conversion :
  956.  
  957.    to_integer: INTEGER is
  958.          -- Current must looks like an INTEGER.
  959.       require
  960.          is_integer
  961.       local
  962.          i, state: INTEGER;
  963.          cc: CHARACTER;
  964.          minus: BOOLEAN;
  965.       do
  966.          -- state 0 : nothing read.
  967.          -- state 1 : "+" or "-" read.
  968.          -- state 2 : in the number.
  969.          -- state 3 : after the number.
  970.          -- state 4 : error.
  971.          from
  972.             i := 1;
  973.          until
  974.             i > count 
  975.          loop
  976.             cc := item(i);
  977.             inspect 
  978.                state
  979.             when 0 then
  980.                if cc.is_separator then
  981.                elseif cc = '+' then
  982.                   state := 1;
  983.                elseif cc = '-' then
  984.                   minus := true;
  985.                   state := 1;
  986.                else
  987.                   check
  988.                      cc.is_digit
  989.                   end;
  990.                   Result := cc.value;
  991.                   state := 2;
  992.                end;
  993.             when 1 then
  994.                if cc.is_separator then
  995.                else
  996.                   check
  997.                      cc.is_digit
  998.                   end;
  999.                   Result := cc.value;
  1000.                   state := 2;
  1001.                end;
  1002.             when 2 then
  1003.                if cc.is_digit then
  1004.                   Result := (Result * 10) + cc.value;
  1005.                else
  1006.                   check
  1007.                      cc.is_separator
  1008.                   end;
  1009.                   state := 3;
  1010.                end;
  1011.             when 3 then
  1012.                check
  1013.                   cc.is_separator
  1014.                end;
  1015.             end;
  1016.             i := i + 1;
  1017.          end;
  1018.          if minus then
  1019.             Result := - Result;
  1020.          end;
  1021.       end; 
  1022.  
  1023.    to_real: REAL is
  1024.          -- Conversion to the corresponding REAL value. 
  1025.          -- The string must looks like a REAL (or like an 
  1026.          -- INTEGER because fractionnal part is optional).
  1027.       require
  1028.          is_integer or is_real
  1029.       do
  1030.          Result := to_double.to_real;
  1031.       end;
  1032.    
  1033.    to_double: DOUBLE is
  1034.          -- Conversion to the corresponding DOUBLE value. 
  1035.          -- The string must looks like a DOUBLE, like 
  1036.          -- a REAL (or like an INTEGER because fractionnal 
  1037.          -- part is optional).
  1038.       require
  1039.          is_integer or is_real or is_double
  1040.       local
  1041.          negative: BOOLEAN;
  1042.          p: POINTER;
  1043.       do
  1044.          tmp_string.copy(Current);
  1045.          tmp_string.left_adjust;
  1046.          if tmp_string.first = '-' then
  1047.             negative := true;
  1048.             tmp_string.remove_first(1);
  1049.          elseif tmp_string.first = '+' then
  1050.             tmp_string.remove_first(1);
  1051.          end;
  1052.          tmp_string.left_adjust;
  1053.          p := tmp_string.to_external;
  1054.          Result := se_string2double(p);
  1055.          if negative then
  1056.             Result := -Result;
  1057.          end;
  1058.       end;
  1059.  
  1060.    binary_to_integer: INTEGER is
  1061.          -- Assume there is enougth space in the INTEGER to store
  1062.          -- the corresponding decimal value.
  1063.       require
  1064.          is_bit;
  1065.          count <= Integer_bits
  1066.       local
  1067.          i: INTEGER;
  1068.       do
  1069.          from
  1070.             i := 1;
  1071.          until
  1072.             i > count
  1073.          loop
  1074.             if item(i) = '1' then
  1075.                Result := (2 * Result) + 1;
  1076.             else
  1077.                Result := 2 * Result;
  1078.             end;
  1079.             i := i + 1;
  1080.          end;
  1081.       end;
  1082.  
  1083.    to_hexadecimal is
  1084.          -- Convert Current bit sequence into the corresponding 
  1085.          -- hexadecimal notation.
  1086.       require
  1087.          is_bit
  1088.       local
  1089.          i, k, new_count: INTEGER;
  1090.          value: INTEGER;
  1091.       do
  1092.          from
  1093.             i := 1;
  1094.             k := count \\ 4;
  1095.             if k > 0 then
  1096.                new_count := 1;
  1097.             end;
  1098.          until
  1099.             k = 0
  1100.          loop
  1101.             value := value * 2 + item(i).value;
  1102.             i := i + 1;
  1103.             k := k - 1;
  1104.          end;
  1105.          if new_count > 0 then
  1106.             put(value.hexadecimal_digit,new_count);
  1107.          end;
  1108.          from
  1109.          until
  1110.             i > count 
  1111.          loop
  1112.             from
  1113.                value := item(i).value;
  1114.                i := i + 1;
  1115.                k := 3;
  1116.             until
  1117.                k = 0
  1118.             loop
  1119.                value := value * 2 + item(i).value;
  1120.                i := i + 1;
  1121.                k := k - 1;
  1122.             end;
  1123.             new_count := new_count + 1;
  1124.             put(value.hexadecimal_digit,new_count);
  1125.          end;
  1126.          count := new_count;
  1127.       end;
  1128.  
  1129. feature -- Printing :
  1130.    
  1131.    out_in_tagged_out_memory is
  1132.       do
  1133.          tagged_out_memory.append(Current); 
  1134.       end;
  1135.    
  1136.    fill_tagged_out_memory is
  1137.       do
  1138.          tagged_out_memory.append("count: "); 
  1139.          count.append_in(tagged_out_memory);
  1140.          tagged_out_memory.append("capacity: "); 
  1141.          capacity.append_in(tagged_out_memory);
  1142.          tagged_out_memory.append("storage: %""); 
  1143.          tagged_out_memory.append(Current); 
  1144.          tagged_out_memory.extend('%"'); 
  1145.       end;
  1146.    
  1147. feature -- Other features :
  1148.    
  1149.    substring(min_index, max_index: INTEGER): like Current is
  1150.          -- New string consisting of items [`min_index'.. `max_index'].  
  1151.       require
  1152.          1 <= min_index;
  1153.          max_index <= count; 
  1154.          min_index <= max_index + 1
  1155.       local
  1156.      c: INTEGER;
  1157.       do
  1158.      c := max_index - min_index + 1;
  1159.      !!Result.make(c);
  1160.      Result.set_count(c);
  1161.          Result.storage.copy_slice(0,storage,min_index - 1, max_index - 1);
  1162.       ensure
  1163.          Result.count = (max_index - min_index + 1)
  1164.       end;
  1165.    
  1166.    extend_multiple(c: CHARACTER; n: INTEGER) is
  1167.          -- Extend Current with `n' times character `c'.
  1168.       require
  1169.          n >= 0
  1170.       local
  1171.          i: INTEGER;
  1172.       do
  1173.          from
  1174.             i := n;
  1175.          until
  1176.             i = 0
  1177.          loop
  1178.             extend(c);
  1179.             i := i - 1;
  1180.          end;
  1181.       ensure
  1182.          count = n + old count
  1183.       end;
  1184.  
  1185.    precede_multiple(c: CHARACTER; n: INTEGER) is
  1186.          -- Prepend `n' times character `c' to Current.
  1187.       require
  1188.          n >= 0
  1189.       local
  1190.          old_count: INTEGER;
  1191.       do
  1192.          if n > 0 then
  1193.             old_count := count;
  1194.             if old_count = 0 then
  1195.                extend_multiple(c,n);
  1196.             else
  1197.                extend_multiple('%U',n);
  1198.                storage.move(0,old_count - 1,n);
  1199.                storage.set_all_with(c,n - 1);
  1200.             end;
  1201.          end;
  1202.       ensure
  1203.          count = n + old count
  1204.       end;
  1205.  
  1206.    extend_to_count(c: CHARACTER; needed_count: INTEGER) is
  1207.          -- Extend Current with `c' until `needed_count' is reached.
  1208.          -- Do nothing if `needed_count' is already greater or equal 
  1209.          -- to `count'.
  1210.       require
  1211.          needed_count >= 0
  1212.       local
  1213.          offset: INTEGER;
  1214.       do
  1215.          from
  1216.             offset := needed_count - count;
  1217.          until
  1218.             offset <= 0
  1219.          loop
  1220.             extend(c);
  1221.             offset := offset - 1;
  1222.          end;
  1223.       ensure
  1224.          count >= needed_count
  1225.       end;
  1226.  
  1227.    precede_to_count(c: CHARACTER; needed_count: INTEGER) is
  1228.          -- Prepend `c' to Current until `needed_count' is reached.
  1229.          -- Do nothing if `needed_count' is already greater or equal 
  1230.          -- to `count'.
  1231.       require
  1232.          needed_count >= 0
  1233.       local
  1234.          offset, old_count: INTEGER;
  1235.       do
  1236.          old_count := count;
  1237.          offset := needed_count - old_count;
  1238.          if offset > 0 then
  1239.             extend_to_count('%U',needed_count);
  1240.             storage.move(0,old_count - 1,offset);
  1241.             storage.set_all_with(c,offset - 1);
  1242.          end;
  1243.       ensure
  1244.          count >= needed_count
  1245.       end;
  1246.  
  1247.    reverse is
  1248.          -- Reverse the string.
  1249.       local
  1250.          i1, i2: INTEGER;
  1251.       do
  1252.          from  
  1253.             i1 := 1;
  1254.             i2 := count;
  1255.          until
  1256.             i1 >= i2
  1257.          loop
  1258.             swap(i1,i2);
  1259.             i1 := i1 + 1;
  1260.             i2 := i2 - 1;
  1261.          end;
  1262.       end;
  1263.    
  1264.    remove_all_occurrences(ch: CHARACTER) is
  1265.          -- Remove all occurrences of `ch'.
  1266.       local
  1267.          i, j: INTEGER;
  1268.       do
  1269.          from  
  1270.             i := 1;
  1271.             j := 1;
  1272.          until
  1273.             i > count
  1274.          loop
  1275.             if item(i) /= ch then
  1276.                put(item(i),j);
  1277.                j := j + 1;
  1278.             end;
  1279.             i := i + 1;
  1280.          end;
  1281.          count := j - 1; 
  1282.       ensure
  1283.          count = old count - old nb_occurrences(ch)
  1284.       end;
  1285.  
  1286.    substring_index(other: STRING; start: INTEGER): INTEGER is
  1287.          -- Position of first occurrence of `other' at or after 
  1288.          -- `start';
  1289.          -- 0 if none.
  1290.       require
  1291.          start_large_enough: start >= 1;
  1292.          start_small_enough: start <= count;
  1293.          string_exist: other /= Void
  1294.       local
  1295.          i, s: INTEGER;
  1296.       do
  1297.          from
  1298.             s := start;
  1299.          until
  1300.             Result /= 0 or else (s + other.count - 1) > count
  1301.          loop
  1302.             from
  1303.                i := 1;
  1304.             until
  1305.                i > other.count or else item(s + i - 1) /= other.item(i)
  1306.             loop
  1307.                i := i + 1;
  1308.             end;
  1309.             if i > other.count then
  1310.                Result := s;
  1311.             else
  1312.                s := s + 1
  1313.             end;
  1314.          end;
  1315.       end;
  1316.  
  1317. feature -- Splitting a STRING :
  1318.    
  1319.    split: ARRAY[STRING] is
  1320.          -- Split the string into an array of words.
  1321.          -- Uses `is_separator' of CHARACTER to find words.
  1322.          -- Gives Void or a non empty array.
  1323.       do
  1324.          if count > 0 then
  1325.             split_buffer.clear;
  1326.             split_in(split_buffer);
  1327.             if not split_buffer.is_empty then
  1328.                Result := split_buffer.twin;
  1329.             end;
  1330.          end;
  1331.       ensure
  1332.          Result /= Void implies not Result.is_empty
  1333.       end;
  1334.  
  1335.    split_in(words: COLLECTION[STRING]) is
  1336.          -- Same jobs as `split' but result is appended in `words'.
  1337.       require
  1338.          words /= Void
  1339.       local 
  1340.          state, i: INTEGER;
  1341.          -- state = 0 : waiting next word.
  1342.          -- state = 1 : inside a new word.
  1343.          c: CHARACTER;
  1344.       do
  1345.          if count > 0 then
  1346.             from
  1347.                i := 1;
  1348.             until
  1349.                i > count
  1350.             loop
  1351.                c := item(i);
  1352.                if state = 0 then
  1353.                   if not c.is_separator then
  1354.                      tmp_string.clear;
  1355.                      tmp_string.extend(c);
  1356.                      state := 1;
  1357.                   end;
  1358.                else
  1359.                   if not c.is_separator then
  1360.                      tmp_string.extend(c);
  1361.                   else
  1362.                      words.add_last(tmp_string.twin);
  1363.                      state := 0;
  1364.                   end;
  1365.                end;
  1366.                i := i + 1;
  1367.             end;
  1368.             if state = 1 then 
  1369.                words.add_last(tmp_string.twin);
  1370.             end;
  1371.          end;
  1372.       ensure
  1373.          words.count >= old (words.count)
  1374.       end;
  1375.  
  1376. feature -- Other feature :
  1377.  
  1378.    set_last(ch: CHARACTER) is
  1379.       obsolete "Since release -0.77, the new name for this feature %
  1380.                %is `extend_unless'. Please update your code."
  1381.       do
  1382.          extend_unless(ch);
  1383.       end;
  1384.  
  1385.    extend_unless(ch: CHARACTER) is
  1386.          -- Extend `Current' (using `extend') with `ch' unless `ch' is 
  1387.          -- already the `last' character.
  1388.       do
  1389.          if count = 0 or else item(count) /= ch then
  1390.             extend(ch);
  1391.          end;
  1392.       ensure
  1393.          last = ch;
  1394.          count >= old count
  1395.       end;
  1396.  
  1397.    get_new_iterator: ITERATOR[CHARACTER] is
  1398.       do
  1399.          !ITERATOR_ON_STRING!Result.make(Current);
  1400.       end;
  1401.  
  1402. feature -- Interfacing with C string :
  1403.    
  1404.    to_external: POINTER is
  1405.          -- Gives C access to the internal `storage' (may be dangerous).
  1406.          -- To be compatible with C, a null character is added at the end 
  1407.          -- of the internal `storage'. This extra null character is not 
  1408.          -- part of the Eiffel STRING. 
  1409.       do
  1410.          if capacity > count then
  1411.             count := count + 1;
  1412.             if item(count) /= '%U' then
  1413.                put('%U',count);
  1414.             end;
  1415.          else
  1416.             extend('%U');
  1417.          end;
  1418.          count := count - 1;
  1419.          Result := storage.to_pointer;
  1420.       ensure
  1421.          count = old count;
  1422.          Result.is_not_null
  1423.       end;
  1424.  
  1425.    from_external(p: POINTER) is
  1426.          -- Internal `storage' is set using `p' (may be dangerous because
  1427.          -- the external C string `p' is not duplicated).
  1428.          -- Assume `p' has a null character at the end in order to 
  1429.          -- compute the Eiffel `count'. This extra null character
  1430.          -- is not part of the Eiffel STRING.
  1431.          -- Also consider `from_external_copy' to choose the most appropriate. 
  1432.       require
  1433.          p.is_not_null
  1434.       do
  1435.          from
  1436.             storage := storage.from_pointer(p);
  1437.             count := 0;
  1438.          until
  1439.             storage.item(count) = '%U'
  1440.          loop
  1441.             count := count + 1;
  1442.          end;
  1443.          capacity := count + 1;
  1444.       ensure
  1445.          capacity = count + 1;
  1446.          p = to_external
  1447.       end;
  1448.  
  1449.    from_external_copy(p: POINTER) is
  1450.          -- Internal `storage' is set using a copy of `p'.
  1451.          -- Assume `p' has a null character at the end in order to 
  1452.          -- compute the Eiffel `count'. This extra null character
  1453.          -- is not part of the Eiffel STRING.
  1454.          -- Also consider `from_external' to choose the most appropriate.
  1455.       local
  1456.          s: like storage;
  1457.          i: INTEGER;
  1458.       do
  1459.          clear;
  1460.          from
  1461.             s := s.from_pointer(p);
  1462.             i := 0;
  1463.          until
  1464.             s.item(i) = '%U'
  1465.          loop
  1466.             extend(s.item(i));
  1467.             i := i + 1;
  1468.          end;
  1469.       end;
  1470.  
  1471. feature -- Other feature here for ELKS'95 compatibility :
  1472.  
  1473.    make_from_string(model: STRING) is
  1474.          -- Initialize from the characters of `model'.
  1475.          -- (Useful in proper descendants of class STRING, to 
  1476.          -- initialize a string-like object from a manifest string.)
  1477.       require
  1478.          model /= Void
  1479.       do
  1480.      if capacity < model.count then
  1481.         capacity := model.count;
  1482.         storage := storage.calloc(capacity);
  1483.      end;
  1484.      count := model.count;
  1485.      storage.copy_from(model.storage,count - 1);
  1486.       ensure
  1487.          count = model.count
  1488.       end;
  1489.  
  1490.    head(n: INTEGER) is
  1491.       -- Remove all characters except fo the first `n'.
  1492.       -- Do nothing if n >= count.
  1493.       require
  1494.          n >= 0
  1495.       do
  1496.          if n < count then
  1497.             remove_last(count - n);
  1498.          end;
  1499.       ensure
  1500.          count = n.min(old count)
  1501.       end;
  1502.    
  1503.    tail(n: INTEGER) is
  1504.       -- Remove all characters except for the last `n'.
  1505.       -- Do nothing if n >= count.
  1506.       require
  1507.          n >= 0
  1508.       do
  1509.          if n < count then
  1510.             remove_first(count - n);
  1511.          end;
  1512.       ensure
  1513.          count = n.min(old count)
  1514.       end;
  1515.  
  1516. feature {STRING}
  1517.  
  1518.    set_count(new_count: INTEGER) is
  1519.       do
  1520.      count := new_count;
  1521.       end;
  1522.  
  1523.    se_string2double(number_view: POINTER):DOUBLE is
  1524.       external "SmallEiffel"
  1525.       end; 
  1526.  
  1527. feature {NONE}
  1528.    
  1529.    tmp_string: STRING is 
  1530.       once
  1531.          !!Result.make(256);
  1532.       end;
  1533.  
  1534.    split_buffer: ARRAY[STRING] is
  1535.       once
  1536.          !!Result.with_capacity(4,1);
  1537.       end;
  1538.  
  1539. invariant
  1540.  
  1541.    0 <= count;
  1542.  
  1543.    count <= capacity;
  1544.  
  1545.    capacity > 0 implies storage.is_not_null;
  1546.    
  1547. end -- STRING
  1548.